#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <string.h>
#include "log.hpp"
#include "epoll.hpp"
#include "Threadpool.hpp"
#define BUF_SIZE 1024

class Tcpserver
{
public:
    Tcpserver(uint16_t port, std::string ip = "")
        : port_(port), ip_(ip), listenfd_(-1)
    {
        listenfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (listenfd_ < 0)
        {
            log(FATAL, "create Tcpserver socket err");
            exit(-1);
        }
        struct sockaddr_in local;
        local.sin_addr.s_addr = ip.empty() ? htonl(INADDR_ANY) : inet_addr(ip.c_str());
        local.sin_port = htons(port_);
        local.sin_family = AF_INET;
        if (bind(listenfd_, (const sockaddr *)&local, sizeof(local)) < 0)
        {
            log(FATAL, "Tcpserver bind err");
            exit(-1);
        }
        log(DEBUG, "server bind success");
    }
    static void tranService(ConnClient *conn)
    {
        while (true)
        {
            char buffer[BUF_SIZE];
            ssize_t s = read(conn->sockfd_, buffer, sizeof(buffer));
            if (s > 0)
            {
                buffer[s] = '\0';
                log(INFO, "[%s:%d]# %s", conn->ip_.c_str(), conn->port_, buffer);
            }
            else if (s == 0)
            {
                // 客户端退出，close fd
                close(conn->sockfd_);
                log(DEBUG, "[%s:%d exit]", conn->ip_.c_str(), conn->port_);
                return;
            }
            else
            {
                continue;
            }
        }
    }
    void loop()
    {
        // 启动线程池
        pool = Threadpool::GetInstance(12);
        pool->loop();
        // Tcp面向连接，listen 监听连接请求
        listen(listenfd_, 5);
        // 创建epoll  注册监听事件
        Epoll epoll(listenfd_);
        TcpSocket ts(ip_, port_, listenfd_);
        epoll.Add(ts);
        // 事件循环
        while (true)
        {
            std::vector<TcpSocket> FdWaitQueue;
            if (!epoll.Wait(FdWaitQueue))
            {
                continue;
            }
            for (auto &elem : FdWaitQueue)
            {
                // 监听事件就绪，创建连接
                if (elem.sockfd_ == listenfd_)
                {
                    struct sockaddr_in peer;
                    socklen_t len = sizeof(peer);
                    int sockfd = accept(listenfd_, (struct sockaddr *)&peer, &len);
                    if (sockfd < 0)
                    {
                        log(DEBUG, "accept err");
                    }
                    else
                    {
                        TcpSocket ts(inet_ntoa(peer.sin_addr), ntohs(peer.sin_port), sockfd);
                        epoll.Add(ts);
                    }
                }
                else
                {
                    ConnClient *conn = new ConnClient(elem.sockfd_, elem.port_, elem.ip_);
                    pool->addTask(tranService, conn);
                }
            }
        }
    }

    ~Tcpserver()
    {
        close(listenfd_);
    }

private:
    int listenfd_;
    std::string ip_;
    uint16_t port_;
    static Threadpool *pool;
};
Threadpool *Tcpserver::pool = nullptr;

int main(int argc, char *argv[])
{
    if (argc != 2 && argc != 3)
    {
        log(FATAL, "Usage:%s [port:ip]", argv[0]);
        exit(-1);
    }
    if (argc == 2)
    {
        Tcpserver svr(atoi(argv[1]));
        svr.loop();
    }
    else
    {
        std::string ip = argv[2];
        Tcpserver svr(atoi(argv[1]), ip);
        svr.loop();
    }
}

// #define BUFFER_SIZE 1024

// struct session_key
// {
//     std::string src_ip;
//     std::string dst_ip;
//     uint16_t src_port;
//     uint16_t dst_port;
// };
// bool cmp(struct tcphdr *lhs,struct tcphdr *rhs)
// {
//     return lhs->seq < lhs->seq;
// }
// int main()
// {
//     int sockfd = socket(AF_INET, SOCK_STREAM, 0);

//     if (sockfd < 0)
//     {
//         exit(-1);
//     }
//     struct sockaddr_in servaddr;
//     bzero(&servaddr, sizeof(servaddr));
//     servaddr.sin_family = AF_INET;
//     servaddr.sin_port = htons(8080);
//     inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
//     connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
//     std::unordered_map<struct session_key, std::vector<struct tcphdr *>> tcp_header;
//     while (true)
//     {
//         char buffer[BUFFER_SIZE];
//         ssize_t n = recv(sockfd, buffer, sizeof(buffer), 0);
//         if (n < 0)
//         {
//             exit(-1);
//         }
//         else if (n == 0)
//         {
//             break;
//         }
//         else
//         {
//             struct iphdr *iph = (struct iphdr *)(buffer);
//             struct tcphdr *tcph = (struct tcphdr *)(buffer + sizeof(struct iphdr));
//             session_key key;
//             key.src_ip = ntohl(iph->saddr);
//             key.src_port = ntohs(tcph->source);
//             key.dst_ip = ntohl(iph->daddr);
//             key.dst_port = ntohs(tcph->dest);

//             tcp_header[key].push_back(tcph);
//         }
//     }
//     for(auto &e:tcp_header)
//     {
//         std::sort(e.second.begin(),e.second.end());
//     }
// }